package com.jctrip.hotel.management.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jctrip.hotel.common.enums.SourceEnum;
import com.jctrip.hotel.common.util.BeanUtil;
import com.jctrip.hotel.common.util.RandomUtil;
import com.jctrip.hotel.domain.dao.*;
import com.jctrip.hotel.domain.entity.*;
import com.jctrip.hotel.management.model.param.*;
import com.jctrip.hotel.management.model.param.InsertSourceInfoParam;
import com.jctrip.hotel.management.model.param.RemoveSourceInfoParam;
import com.jctrip.hotel.management.model.param.UpdateSourceInfoParam;
import com.jctrip.hotel.management.model.result.GetAllSourceListResult;
import com.jctrip.hotel.management.model.result.GetSourceCodeResult;
import com.jctrip.hotel.management.model.result.GetSourceHotelsResult;
import com.jctrip.hotel.management.model.result.GetSourceNameResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SourceInfoService {

    @Autowired
    private HtSourceInfoDao htSourceInfoDao;

    @Autowired
    private HtSourceCodeDao htSourceCodeDao;

    @Autowired
    private HtHotelStdInfoDao htHotelStdInfoDao;

    @Autowired
    private HtRoomTypeStdInfoDao htRoomTypeStdInfoDao;

    @Autowired
    private HtPriceCalendarDao htPriceCalendarDao;

    @Autowired
    private HtPriceCalendarAtourDao htPriceCalendarAtourDao;

    @Autowired
    private HtPriceCalendarRezenDao htPriceCalendarRezenDao;

    @Autowired
    private HtRoomTypeStdInfoCnbeDao htRoomTypeStdInfoCnbeDao;

    @Autowired
    private HtPriceCalendarElongDao htPriceCalendarElongDao;

    @Autowired
    private HtPriceCalendarCnbeDao htPriceCalendarCnbeDao;

    @Autowired
    private HtPriceCalendarGreentreeDao htPriceCalendarGreentreeDao;

    public GetSourceNameResult listName(GetSourceNameParam param) {
        List<HtSourceInfo> htSourceInfos = htSourceInfoDao.selectList(new LambdaQueryWrapper<HtSourceInfo>()
                .eq(StringUtils.isNotBlank(param.getSourceCode()), HtSourceInfo::getSourceCode, param.getSourceCode())
                .select(HtSourceInfo::getId, HtSourceInfo::getSourceId,
                        HtSourceInfo::getSourceCode, HtSourceInfo::getSourceName));

        List<GetSourceNameResult.SourceInfo> sourceInfos = htSourceInfos.stream().map(item -> {
            GetSourceNameResult.SourceInfo sourceInfo = GetSourceNameResult.SourceInfo.builder().build();
            BeanUtil.copyProperties(item, sourceInfo);
            return sourceInfo;
        }).collect(Collectors.toList());

        return GetSourceNameResult.builder()
                .sourceInfoList(sourceInfos)
                .build();
    }

    public GetSourceCodeResult listCodeName() {
        List<HtSourceCode> htSourceCodes = htSourceCodeDao.selectList(new LambdaQueryWrapper<HtSourceCode>()
                .select(HtSourceCode::getId, HtSourceCode::getCode,
                        HtSourceCode::getName));

        List<GetSourceCodeResult.SourceCodeInfo> sourceInfos = htSourceCodes.stream().map(item -> {
            GetSourceCodeResult.SourceCodeInfo sourceInfo = GetSourceCodeResult.SourceCodeInfo.builder().build();
            BeanUtil.copyProperties(item, sourceInfo);
            return sourceInfo;
        }).collect(Collectors.toList());

        return GetSourceCodeResult.builder()
                .sourceCodeList(sourceInfos)
                .build();
    }

    public GetSourceHotelsResult listHotels(GetSourceHotelsParam param) {
        if (SourceEnum.CNBE.getCode().equals(param.getSourceCode())
                || SourceEnum.CNBEINT.getCode().equals(param.getSourceCode())) {
            return getCnbeHotels(param);
        }
        List<HtHotelStdInfo> htHotelStdInfos = htHotelStdInfoDao.selectList(new LambdaQueryWrapper<HtHotelStdInfo>()
                .eq(HtHotelStdInfo::getSourceCode, param.getSourceCode())
                .and(e -> e.like(HtHotelStdInfo::getHotelId, param.getHotelInfo())
                        .or().like(HtHotelStdInfo::getHotelName, param.getHotelInfo()))
                .eq(HtHotelStdInfo::getSourceStatus, 1)
                .eq(HtHotelStdInfo::getBookStatus, 1)
                .select(HtHotelStdInfo::getHotelId, HtHotelStdInfo::getHotelTel,
                        HtHotelStdInfo::getHotelAddress, HtHotelStdInfo::getHotelName,
                        HtHotelStdInfo::getSourceCode)
                .last("limit 10"));
        List<GetSourceHotelsResult.HotelInfo> hotelInfoList = new ArrayList<>();
        AtomicReference<Long> Id = new AtomicReference<>(1L);
        htHotelStdInfos.forEach(htHotelStdInfo -> {
            GetSourceHotelsResult.HotelInfo hotelInfo = GetSourceHotelsResult.HotelInfo.builder()
                    .hotelId(htHotelStdInfo.getHotelId()).id(Id.getAndSet(Id.get() + 1))
                    .hotelTel(htHotelStdInfo.getHotelTel())
                    .hotelAddress(htHotelStdInfo.getHotelAddress())
                    .hotelName(htHotelStdInfo.getHotelName()).build();
            List<HtRoomTypeStdInfo> htRoomTypeStdInfos = htRoomTypeStdInfoDao.selectList(new LambdaQueryWrapper<HtRoomTypeStdInfo>()
                    .eq(HtRoomTypeStdInfo::getHotelId, htHotelStdInfo.getHotelId())
                    .select(HtRoomTypeStdInfo::getRoomTypeCode, HtRoomTypeStdInfo::getRoomTypeName));
            List<GetSourceHotelsResult.RoomInfo> roomInfos = new ArrayList<>();
            AtomicReference<Long> id = new AtomicReference<>(1L);
            htRoomTypeStdInfos.forEach(htRoomTypeStdInfo -> {
                //将没有价库信息的房型过滤掉
                Long count = getPriceCalendarCount(htHotelStdInfo.getSourceCode(), htHotelStdInfo.getHotelId(),
                        htRoomTypeStdInfo.getRoomTypeCode());
                if (count <= 0) {
                    return;
                }
                GetSourceHotelsResult.RoomInfo roomInfo = GetSourceHotelsResult.RoomInfo.builder()
                        .id(id.getAndSet(id.get() + 1))
                        .roomTypeCode(htRoomTypeStdInfo.getRoomTypeCode())
                        .roomTypeName(htRoomTypeStdInfo.getRoomTypeName())
                        .build();
                roomInfos.add(roomInfo);
            });
            hotelInfo.setRoomInfos(roomInfos);
            hotelInfoList.add(hotelInfo);
        });
        return GetSourceHotelsResult.builder().hotelInfoList(hotelInfoList).build();
    }

    public GetAllSourceListResult listAllSources(String sourceCode, String name, Long pageNo, Long pageSize) {
        LambdaQueryWrapper<HtSourceInfo> htSourceInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(sourceCode)) {
            htSourceInfoLambdaQueryWrapper.eq(HtSourceInfo::getSourceCode, sourceCode);
        }
        if (StringUtils.isNotBlank(name)) {
            htSourceInfoLambdaQueryWrapper.like(HtSourceInfo::getSourceName, name);
        }
        Page<HtSourceInfo> htSourceInfoPage = new Page<>();
        htSourceInfoPage.setSize(pageSize);
        htSourceInfoPage.setCurrent(pageNo);
        Page<HtSourceInfo> sourceInfoPage = htSourceInfoDao.selectPage(htSourceInfoPage, htSourceInfoLambdaQueryWrapper);
        List<GetAllSourceListResult.SourceInfo> sourceInfoList = new ArrayList<>();

        sourceInfoPage.getRecords().forEach(htSourceInfo -> {
            GetAllSourceListResult.SourceInfo sourceInfo = GetAllSourceListResult.SourceInfo.builder().build();
            BeanUtil.copyProperties(htSourceInfo, sourceInfo);
            sourceInfo.setId(String.valueOf(htSourceInfo.getId()));
            sourceInfo.setType(Optional.ofNullable(htSourceCodeDao.selectOne(new LambdaQueryWrapper<HtSourceCode>()
                    .eq(HtSourceCode::getCode, htSourceInfo.getSourceCode())))
                    .orElse(new HtSourceCode())
                    .getName());
            sourceInfo.setName(htSourceInfo.getSourceName());
            sourceInfo.setAppId(htSourceInfo.getSourceAppId());
            sourceInfo.setSecretKey(htSourceInfo.getSourceSecret());
            sourceInfo.setStatus(htSourceInfo.getSourceStatus());
            sourceInfoList.add(sourceInfo);
        });

        return GetAllSourceListResult.builder()
                .current(sourceInfoPage.getCurrent())
                .size(sourceInfoPage.getSize())
                .total(sourceInfoPage.getTotal())
                .pages(sourceInfoPage.getPages())
                .records(sourceInfoList)
                .build();
    }

    public List<GetAllSourceListResult.SourceInfo> listAll() {
        LambdaQueryWrapper<HtSourceInfo> htSourceInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        htSourceInfoLambdaQueryWrapper.select(HtSourceInfo::getSourceId, HtSourceInfo::getSourceName);
        List<HtSourceInfo> htSourceInfos = htSourceInfoDao.selectList(htSourceInfoLambdaQueryWrapper);
        List<GetAllSourceListResult.SourceInfo> sourceInfoList = new ArrayList<>();

        htSourceInfos.forEach(htSourceInfo -> {
            GetAllSourceListResult.SourceInfo sourceInfo = GetAllSourceListResult.SourceInfo.builder().build();
            BeanUtil.copyProperties(htSourceInfo, sourceInfo);
            sourceInfo.setId(String.valueOf(htSourceInfo.getId()));
            sourceInfo.setName(htSourceInfo.getSourceName());
            sourceInfoList.add(sourceInfo);
        });

        return sourceInfoList;
    }

    public String editSourceInfo(UpdateSourceInfoParam param) {
        if (StringUtils.isBlank(param.getId())) {
            throw new RuntimeException("主键不能为空");
        }
        if (StringUtils.isBlank(param.getSourceCode())) {
            throw new RuntimeException("供应渠道不能为空");
        }
        if (StringUtils.isBlank(param.getName())) {
            throw new RuntimeException("供应名不能为空");
        }
        if (StringUtils.isBlank(param.getAppId())) {
            throw new RuntimeException("AppId不能为空");
        }
        if (null == param.getStatus()) {
            throw new RuntimeException("供应状态不能为空");
        }
        HtSourceInfo htSourceInfo = new HtSourceInfo();
        BeanUtil.copyProperties(param, htSourceInfo);
        htSourceInfo.setSourceName(param.getName());
        htSourceInfo.setSourceAppId(param.getAppId());
        htSourceInfo.setSourceSecret(param.getSecretKey());
        htSourceInfo.setSourceStatus(param.getStatus());
        htSourceInfo.setId(Long.valueOf(param.getId()));
        return htSourceInfoDao.updateById(htSourceInfo) == 1 ? "编辑成功!" : "编辑失败!";
    }

    public String addSourceInfo(InsertSourceInfoParam param) {
        if (StringUtils.isBlank(param.getSourceCode())) {
            throw new RuntimeException("供应渠道不能为空");
        }
        if (StringUtils.isBlank(param.getName())) {
            throw new RuntimeException("供应名不能为空");
        }
        if (StringUtils.isBlank(param.getAppId())) {
            throw new RuntimeException("AppId不能为空");
        }
        if (null == param.getStatus()) {
            throw new RuntimeException("供应状态不能为空");
        }
        HtSourceInfo htSourceInfo = new HtSourceInfo();
        String sourceId = null;
        Random random = new Random();
        while (htSourceInfo != null) {
            sourceId = (random.nextInt(9) + 1) + RandomUtil.createRandomNum(7);
            htSourceInfo = htSourceInfoDao.selectOne(new LambdaQueryWrapper<HtSourceInfo>()
                    .eq(HtSourceInfo::getSourceId, sourceId));
        }
        htSourceInfo = new HtSourceInfo();
        BeanUtil.copyProperties(param, htSourceInfo);
        htSourceInfo.setSourceName(param.getName());
        htSourceInfo.setSourceAppId(param.getAppId());
        htSourceInfo.setSourceSecret(param.getSecretKey());
        htSourceInfo.setSourceStatus(param.getStatus());
        htSourceInfo.setSourceId(sourceId);
        return htSourceInfoDao.insert(htSourceInfo) == 1 ? "新增成功!" : "新增失败!";
    }

    public String deleteSourceInfo(RemoveSourceInfoParam param) {
        if (StringUtils.isBlank(param.getId())) {
            throw new RuntimeException("删除主键不能为空");
        }
        return htSourceInfoDao.deleteById(Long.valueOf(param.getId())) == 1 ? "删除成功!" : "删除失败!";
    }

    private Long getPriceCalendarCount(String sourceCode,String hotelId, String roomTypeCode) {
        Long count;
        SourceEnum sourceEnum = SourceEnum.getByCode(sourceCode);
        if (sourceEnum == null) {
            throw new RuntimeException("无效的sourceCode=" + sourceCode);
        }
        switch (sourceEnum){
            case ATOUR:
                count = htPriceCalendarAtourDao.selectCount(new LambdaQueryWrapper<HtPriceCalendarAtour>()
                        .eq(HtPriceCalendarAtour::getHotelId, hotelId)
                        .eq(HtPriceCalendarAtour::getRoomTypeCode, roomTypeCode));
                break;
            case REZEN:
                count = htPriceCalendarRezenDao.selectCount(new LambdaQueryWrapper<HtPriceCalendarRezen>()
                        .eq(HtPriceCalendarRezen::getHotelId, hotelId)
                        .eq(HtPriceCalendarRezen::getRoomTypeCode, roomTypeCode));
                        break;
            case GREENTREE:
                count = htPriceCalendarGreentreeDao.selectCount(new LambdaQueryWrapper<HtPriceCalendarGreentree>()
                        .eq(HtPriceCalendarGreentree::getHotelId, hotelId)
                        .eq(HtPriceCalendarGreentree::getRoomTypeCode, roomTypeCode));
                break;
            case ELONGDOM:
                count  = htPriceCalendarElongDao.selectCount(new LambdaQueryWrapper<HtPriceCalendarElong>()
                        .eq(HtPriceCalendarElong::getHotelId, hotelId)
                        .eq(HtPriceCalendarElong::getRoomTypeCode, roomTypeCode));
                break;
            default:
                count = htPriceCalendarDao.selectCount(new LambdaQueryWrapper<HtPriceCalendar>()
                        .eq(HtPriceCalendar::getHotelId, hotelId)
                        .eq(HtPriceCalendar::getRoomTypeCode, roomTypeCode));
                break;
        }
        return count;
    }

    private GetSourceHotelsResult getCnbeHotels(GetSourceHotelsParam param) {
        List<HtHotelStdInfo> htHotelStdInfos = htHotelStdInfoDao.selectList(new LambdaQueryWrapper<HtHotelStdInfo>()
                .eq(HtHotelStdInfo::getSourceCode, param.getSourceCode())
                .and(e -> e.like(HtHotelStdInfo::getHotelId, param.getHotelInfo()).or().like(HtHotelStdInfo::getHotelName, param.getHotelInfo()))
                .eq(HtHotelStdInfo::getSourceStatus, 1).eq(HtHotelStdInfo::getBookStatus, 1)
                .select(HtHotelStdInfo::getHotelId, HtHotelStdInfo::getHotelTel, HtHotelStdInfo::getHotelAddress, HtHotelStdInfo::getHotelName,
                        HtHotelStdInfo::getHotelNameEn)
                .last("limit 10"));
        List<GetSourceHotelsResult.HotelInfo> hotelInfoList = new ArrayList<>();
        AtomicReference<Long> Id = new AtomicReference<>(1L);
        htHotelStdInfos.forEach(htHotelStdInfo -> {
            GetSourceHotelsResult.HotelInfo hotelInfo = GetSourceHotelsResult.HotelInfo.builder()
                    .hotelId(htHotelStdInfo.getHotelId()).id(Id.getAndSet(Id.get() + 1))
                    .hotelTel(htHotelStdInfo.getHotelTel())
                    .hotelAddress(htHotelStdInfo.getHotelAddress())
                    .hotelName(StringUtils.isNotBlank(htHotelStdInfo.getHotelName()) ? htHotelStdInfo.getHotelName() : htHotelStdInfo.getHotelNameEn())
                    .build();
            List<HtRoomTypeStdInfo> htRoomTypeStdInfos = htRoomTypeStdInfoDao.selectList(
                    new LambdaQueryWrapper<HtRoomTypeStdInfo>()
                            .eq(HtRoomTypeStdInfo::getHotelId, hotelInfo.getHotelId()));
            List<GetSourceHotelsResult.RoomInfo> roomInfos = new ArrayList<>();
            AtomicReference<Long> id = new AtomicReference<>(1L);
            htRoomTypeStdInfos.forEach(htRoomTypeStdInfo -> {
                //将没有价库信息的房型过滤掉
                Long count = htPriceCalendarCnbeDao.selectCount(new LambdaQueryWrapper<HtPriceCalendarCnbe>()
                        .eq(HtPriceCalendarCnbe::getHotelId, htHotelStdInfo.getHotelId())
                        .eq(HtPriceCalendarCnbe::getRoomTypeCode, htRoomTypeStdInfo.getRoomTypeCode()));
                if (count <= 0) {
                    return;
                }
                GetSourceHotelsResult.RoomInfo roomInfo = GetSourceHotelsResult.RoomInfo.builder()
                        .id(id.getAndSet(id.get() + 1))
                        .roomTypeCode(htRoomTypeStdInfo.getRoomTypeCode())
                        .roomTypeName(htRoomTypeStdInfo.getRoomTypeName())
                        .build();
                roomInfos.add(roomInfo);
            });
            hotelInfo.setRoomInfos(roomInfos);
            hotelInfoList.add(hotelInfo);
        });
        return GetSourceHotelsResult.builder().hotelInfoList(hotelInfoList).build();
    }
}
